package cn.rocksolid.proxy.restful.sys;

import cn.rocksolid.sport.agency.entity.AgencyEntity;
import cn.rocksolid.sport.agency.service.AgencyService;
import cn.rocksolid.sport.common.C;
import cn.rocksolid.sport.common.Constant.AccessType;
import cn.rocksolid.sport.common.context.RockSolidContext;
import cn.rocksolid.sport.common.context.RockSolidContextHolder;
import cn.rocksolid.sport.common.entity.LoginEntity;
import cn.rocksolid.sport.common.error.RSE;
import cn.rocksolid.sport.common.error.RockSolidException;
import cn.rocksolid.sport.common.http.R;
import cn.rocksolid.sport.common.utils.CaptchaUtils;
import cn.rocksolid.sport.security.entity.UserEntity;
import cn.rocksolid.sport.security.service.CaptchaService;
import cn.rocksolid.sport.security.service.CredentialService;
import cn.rocksolid.sport.security.service.TokenService;
import cn.rocksolid.sport.security.service.UserService;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RestController;

import javax.imageio.ImageIO;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;

/**
 * System user login
 *
 * @author Axl Zhao
 * @email axl.zhao@163.com
 */
@RestController
public class LoginController {

  private final AgencyService agencyService;
  private final UserService userService;
  private final TokenService tokenService;
  private final CaptchaService captchaService;
  private final CredentialService credentialService;

  @Autowired
  public LoginController(final AgencyService agencyService, final UserService userService,
          final TokenService tokenService, final CaptchaService captchaService,
          final CredentialService credentialService) {
    this.agencyService = agencyService;
    this.userService = userService;
    this.tokenService = tokenService;
    this.captchaService = captchaService;
    this.credentialService = credentialService;
  }

  @GetMapping("captcha.jpg")
  public void captcha(final HttpServletResponse response, final String uuid) throws IOException {
    response.setHeader("Cache-Control", "no-store, no-cache");
    response.setContentType("image/jpeg");
    String code = CaptchaUtils.createText();
    captchaService.create(uuid, code);
    ImageIO.write(CaptchaUtils.createImage(code), "jpg", response.getOutputStream());
  }

  @PostMapping("/sys/lookup")
  public Object lookup(@RequestBody final String agencyId) {
    if (StringUtils.isBlank(agencyId)) {
      throw new RockSolidException(RSE.INVALID_PAYLOAD);
    }
    AgencyEntity agency = agencyService.getById(agencyId);
    if (null == agency) {
      throw new RockSolidException(RSE.INVALID_AGENCY_ID);
    }
    return agency;
  }

  /**
   * Login
   */
  @PostMapping("/sys/login")
  public R login(@RequestBody final LoginEntity loginEntity) {
    if (null == loginEntity) {
      throw new RockSolidException(RSE.INVALID_PAYLOAD);
    }
    if (!captchaService.verify(loginEntity.getUuid(), loginEntity.getCaptcha())) {
      throw new RockSolidException(RSE.CAPTCHA_MISMATCH);
    }
    UserEntity u = new UserEntity();
    u.setUsername(loginEntity.getLoginId());
    u.setEmail(loginEntity.getLoginId());
    u.setMobile(loginEntity.getLoginId());
    UserEntity user = userService.exist(u);
    if (null == user) {
      throw new RockSolidException(RSE.INVALID_UID);
    }
    credentialService.verify(user.getId(), AccessType.AGENCY, loginEntity.getPassword());
    String token = tokenService.create(user.getId(), AccessType.AGENCY, TokenService.DEFAULT_TOKEN_EXPIRE);
    return R.ok().put(C.TOKEN.p, token).put(C.EXPIRY.p, TokenService.DEFAULT_TOKEN_EXPIRE);
  }

  /**
   * Logout
   */
  @PostMapping("/sys/logout")
  public R logout() {
    RockSolidContext ctx = RockSolidContextHolder.getContextSafe();
    tokenService.destroy(ctx.getToken(), ctx.getAccessId(), ctx.getAccessType());
    return R.ok();
  }
}
